package com.invengo.module_check.ui.fragment.inventory;

import android.annotation.SuppressLint;
import android.app.Application;
import android.os.Build;

import com.invengo.base.utils.BeanMapperUtils;
import com.invengo.base.utils.BookStateUtils;
import com.invengo.library_db.entity.module_check.BookBean;
import com.invengo.library_db.entity.module_check.ShelfBean;
import com.invengo.library_rfid.classify.AnalyzeImpl;
import com.invengo.library_rfid.classify.RFIDCallBackListener;
import com.invengo.library_rfid.entity.TagInfo;
import com.invengo.module_check.BR;
import com.invengo.module_check.R;
import com.invengo.module_check.data.repsitory.business.BusinessRepsitory;
import com.invengo.module_check.ui.fragment.inventory.item.InventoryItemViewModel;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.functions.Function;
import java8.util.Optional;

import java.util.stream.Collectors;

import androidx.annotation.NonNull;
import androidx.databinding.ObservableArrayList;
import androidx.databinding.ObservableInt;
import androidx.databinding.ObservableList;

import java8.util.function.Predicate;
import java8.util.stream.StreamSupport;
import me.goldze.mvvmhabit.base.BaseViewModel;
import me.goldze.mvvmhabit.binding.command.BindingCommand;
import me.goldze.mvvmhabit.bus.event.SingleLiveEvent;
import me.goldze.mvvmhabit.http.interceptor.logging.LocalLogUtil;
import me.goldze.mvvmhabit.utils.KLog;
import me.goldze.mvvmhabit.utils.RxUtils;
import me.goldze.mvvmhabit.utils.cache.ACache;
import me.goldze.mvvmhabit.utils.cache.AKey;
import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter;
import me.tatarka.bindingcollectionadapter2.ItemBinding;

import static com.invengo.library_db.entity.module_check.BookState.LENG_OUT_IN_SHELF;
import static com.invengo.library_db.entity.module_check.BookState.ERROR_OTHER_SHELF;
import static com.invengo.library_db.entity.module_check.BookState.IN_SHELF;
import static com.invengo.library_db.entity.module_check.BookState.LENG_OUT;
import static com.invengo.library_db.entity.module_check.BookState.NEED_IN_SHELF;

public class InventoryViewModel extends BaseViewModel<BusinessRepsitory> {
    //    public RFIDCallBackListener rfidService = new RFIDCallBackListener(AnalyzeImpl.TO_BOOK, tagInfo -> onScanResult(tagInfo), state -> isReading.set(state));
    public String currentShelfCode;
    public String firstBookBarCode = "";
    public SingleLiveEvent<String> currentShelfName = new SingleLiveEvent<>();
    public ObservableInt inShelfTotal = new ObservableInt(0);
    public ObservableInt inShelfCount = new ObservableInt(0);
    public ObservableInt lengOutCount = new ObservableInt(0);
    public ObservableInt errorCount = new ObservableInt(0);

    public UIChangeObservable ui = new UIChangeObservable();

    public BindingRecyclerViewAdapter adapter = new BindingRecyclerViewAdapter();

    //    public List<BookBean> bookBeans = new ArrayList<>();
    public ObservableList<InventoryItemViewModel> bookItemList = new ObservableArrayList<>();
    public ItemBinding<InventoryItemViewModel> bookitemBinding = ItemBinding.of(BR.viewModel, R.layout.item_inventory);
    public RFIDCallBackListener rfidService =
            new RFIDCallBackListener(AnalyzeImpl.TO_BOOK,
                    tagInfo -> onScanResult(tagInfo),
                    state -> isReading.set(state),
                    cacheKey -> getBookByShelfCode(currentShelfCode));

    public InventoryViewModel(@NonNull Application application) {
        super(application, BusinessRepsitory.getInstance());
        registerRFID(rfidService);
    }

    public String getFirstBookBarCode() {
        return firstBookBarCode;
    }

    /**
     * 添加异常
     *
     * @param bean 豆
     */
    public void addError(BookBean bean) {
        errorCount.set(errorCount.get() + 1);
    }

    /**
     * 添加外借
     *
     * @param bean 豆
     */
    public void addLengOut(BookBean bean) {
        lengOutCount.set(lengOutCount.get() + 1);
    }

    /**
     * 添加在架
     *
     * @param bean 豆
     */
    public void addInShelf(BookBean bean) {
        inShelfCount.set(inShelfCount.get() + 1);
    }

    public List<Integer> getStatistics() {
        List<Integer> temp = new ArrayList<>();
        temp.add(inShelfTotal.get());
        temp.add(inShelfCount.get());
        temp.add(lengOutCount.get());
        temp.add(errorCount.get());
        return temp;
    }


    public class UIChangeObservable {
        public SingleLiveEvent<List<BookBean>> resultEvent = new SingleLiveEvent<>();
        public SingleLiveEvent<List<BookBean>> listingEvent = new SingleLiveEvent<>();
    }

    //    @Override
    public void onScanResult(TagInfo tagInfo) {
        switch (tagInfo.getRfidModel()) {
            case TID:
                if (tagInfo.getScanModel() == AnalyzeImpl.TO_SHELF) {
//                    getShelfByTid(tagInfo.getTag());
                } else
                    getBookByTid(tagInfo.getTag());
                break;
            case EPC:
            case U_DATA:
                if (tagInfo.getScanModel() == AnalyzeImpl.TO_SHELF) {
//                    getShelfByCode(tagInfo.getTag());
                } else
                    getBookByCode(tagInfo.getTag());
                break;
        }
    }

    /**
     * 按Tid查询书本
     *
     * @param tid 标签
     */
    private void getBookByTid(String tid) {
        model.getBookByTid(tid)
                .compose(RxUtils.applySchedulersIO(getLifecycleProvider(), this))
                .subscribe(bookBean -> checkItem(bookBean));
    }

    /**
     * 按Tid查询书本
     *
     * @param code 标签
     */
    @SuppressLint("CheckResult")
    private void getBookByCode(String code) {
        model.getBookByCode(code)
                .compose(RxUtils.applySchedulersIO(getLifecycleProvider(), this))
                .subscribe(bookBean -> checkItem(bookBean));
    }


    /**
     * 清空图书按钮
     */
    public BindingCommand cleanAllData = new BindingCommand(() -> {
        cleanRFIDCache();
        bookItemList.clear();
        inShelfCount.set(0);
        errorCount.set(0);
        getBookByShelfCode(currentShelfCode);
    });

    public BindingCommand checkError = new BindingCommand(() -> {
        cleanRFIDCacheNotStop();
        List<InventoryItemViewModel> collect = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            collect = bookItemList.stream().filter(itemBean -> BookStateUtils.isErrorBook(itemBean.book.getValue().getTip()))
                    .collect(Collectors.toList());
        } else {
            collect = StreamSupport.stream(bookItemList).filter(itemBean -> BookStateUtils.isErrorBook(itemBean.book.getValue().getTip()))
                    .collect(java8.util.stream.Collectors.toList());
        }
        for (InventoryItemViewModel bean : collect) {
            onItemRemove(bean);
        }
        errorCount.set(0);
    });

    /**
     * 检查是否有未上架的图书
     */
    public BindingCommand checkListing = new BindingCommand(() -> {
        List<BookBean> errorBooks = getErrorBooks();
        if (errorBooks.isEmpty()) {
            inventoryBooks();
        } else {
            ui.listingEvent.postValue(errorBooks);
        }
    });

    /**
     * 完成盘点
     */
    public void inventoryBooks() {
//        List<BookBean> bookBeans = getBookBeans();
        model.inventoryBook(tempBeans, currentShelfCode, currentShelfName.getValue(), errorCount.get(), inShelfCount.get(), lengOutCount.get(), inShelfTotal.get() - inShelfCount.get())
                .compose(RxUtils.applySchedulersDialog(getLifecycleProvider(), this))
                .subscribe(updateResult -> {
                    ui.resultEvent.postValue(tempBeans);
                }, throwable -> {
                    ui.resultEvent.postValue(null);
                });
    }

    private List<BookBean> getErrorBooks() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return bookItemList.stream()
                    .map(itemViewModel -> itemViewModel.book.getValue())
                    .filter(bean -> BookStateUtils.isInventoryErrorsBook(bean.getTip()))
                    .collect(Collectors.toList());
        } else {
            return StreamSupport.stream(bookItemList)
                    .map(itemViewModel -> itemViewModel.book.getValue())
                    .filter(bean -> BookStateUtils.isInventoryErrorsBook(bean.getTip()))
                    .collect(java8.util.stream.Collectors.toList());
        }
    }

    /**
     * 上架未上架图书
     */
    public void listingErrorBook(List<BookBean> collect) {
        model.bookListing(collect, currentShelfCode, currentShelfName.getValue())
                .compose(RxUtils.applySchedulersToast(getLifecycleProvider(), this))
                .subscribe(updateResult -> {
                    changeErrorBooks();
                    inventoryBooks();
                });
    }

    public void changeErrorBooks() {
        for (InventoryItemViewModel itemViewModel : bookItemList) {
            BookBean bean = itemViewModel.book.getValue();
            if (BookStateUtils.isInventoryErrorsBook(bean.getTip())) {
                bean.setTip(IN_SHELF);
                itemViewModel.updateState(bean);
            }
        }
        errorCount.set(0);
        inShelfTotal.set(inShelfCount.get());
    }

    private List<BookBean> getBookBeans() {
        return StreamSupport.stream(bookItemList).map(viewModel -> {
            LocalLogUtil.temp2File("----获取一条----  " + viewModel.bookBean.getBookName() + "  " + viewModel.bookBean.getBarCode() + "  " + viewModel.bookBean.getTip() + "  外借状态： " + viewModel.bookBean.getState());
            return viewModel.bookBean;
        }).collect(java8.util.stream.Collectors.toList());
    }

    private List<String> tidList = new ArrayList<>();
    private List<BookBean> tempBeans = new ArrayList<>();

    /**
     * 添加项目
     *
     * @param bean 豆
     */
    private void checkItem(BookBean bean) {
        BookStateUtils.handlerBookState(bean, currentShelfCode, true);
        LocalLogUtil.temp2File("----更新一条数据----  ");
        if (!tidList.contains(bean.getBarCode())) {
            bookItemList.add(new InventoryItemViewModel(this, bean));
            tidList.add(bean.getBarCode());
            tempBeans.add(bean);
        } else {
            StreamSupport.stream(bookItemList).filter(item -> item.book.getValue().getBarCode().equals(bean.getBarCode()))
                    .filter(item -> {
                        if (ACache.getInstance().getAsBoolean(AKey.IS_OFFLINE_MODEL)) {
                            return true;
                        } else {
                            return !item.book.getValue().getTip().equals(bean.getTip()) | item.book.getValue().getTip() != IN_SHELF;
                        }
                    })
                    .findFirst()
                    .ifPresent(itemViewModel -> {
                        KLog.e("跟新数据。。。");
                        itemViewModel.updateState(bean);
                    });
            /**
             * 这里是由于出现了盘点详情跟结果不一致的情况，做了临时处理
             */
            StreamSupport.stream(tempBeans).filter(item -> item.getBarCode().equals(bean.getBarCode())).findFirst()
                    .ifPresent(bean1 -> {
                        bean1.setbLostBookFlag(bean.getbLostBookFlag());
                        bean1.setTip(bean.getTip());
                    });
        }
    }

    private void swapPosition(InventoryItemViewModel itemViewModel) {
        switch (itemViewModel.book.getValue().getTip()) {
            case IN_SHELF:
                KLog.e("正常---> 在架");
            case LENG_OUT:
                KLog.e("bug---> 没有识别到外借");
            case NEED_IN_SHELF:
                KLog.e("bug---> 匹配已上架");
            case LENG_OUT_IN_SHELF:
                KLog.e("正常---> 外借在架");
            case ERROR_OTHER_SHELF:
                KLog.e("开始交换位置");
                break;
        }
    }

    /**
     * 删除一个条目
     */
    public void onItemRemove(InventoryItemViewModel model) {
        int position = getPosition(model);
        tidList.remove(model.book.getValue().getBarCode());
        tempBeans.remove(position);
        bookItemList.remove(position);
        adapter.notifyDataSetChanged();
    }

    /**
     * 更新shelfbean传递过来的数据
     *
     * @param shelfBeans 搁架豆
     */
    public void updateShelfBean(ShelfBean shelfBeans) {
        if (shelfBeans == null)
            return;
        firstBookBarCode = shelfBeans.getFirstBookID();
        currentShelfCode = shelfBeans.getShelfCode();
        currentShelfName.postValue(shelfBeans.getShelfName());
    }


    /**
     * 获取position的方式有很多种,indexOf是其中一种，常见的还有在Adapter中、ItemBinding.of回调里
     */
    public int getPosition(InventoryItemViewModel item) {
        return bookItemList.indexOf(item);
    }


    /**
     * 按书架查询书籍
     *
     * @param shelfCode 标签
     */
    @SuppressLint({"CheckResult"})
    private void getBookByShelfCode(String shelfCode) {
        tidList.clear();
        tempBeans.clear();
        model.getBookByShelfCode(shelfCode)
                .compose(RxUtils.applySchedulersToast(getLifecycleProvider(), this))
                .flatMap(bookBeans -> Observable.fromIterable(bookBeans))
                .toList()
//                .toSortedList((o1, o2) -> o1.getPretendCallNo().compareTo(o2.getPretendCallNo()))
                .subscribe(booklist -> {
                    List<BookBean> beans = Optional.ofNullable(booklist).orElseGet(ArrayList::new);
                    bookItemList.clear();
                    inShelfCount.set(0);
                    errorCount.set(0);
                    lengOutCount.set(0);
                    inShelfTotal.set(beans.size());
                    LocalLogUtil.temp2File("---------开始插入数据------");
                    for (BookBean bean : beans) {
                        BookStateUtils.handlerBookState(bean, currentShelfCode, false);
                        bookItemList.add(new InventoryItemViewModel(InventoryViewModel.this, bean));
                        tempBeans.add(bean);
                        tidList.add(bean.getBarCode());
                    }
                });
    }
}
